<?php
/**
 * Created by PhpStorm.
 * User: admin
 * Date: 2019/1/15
 * Time: 23:05
 */
namespace app\admin\logic;
use app\admin\logic\mqlogic\DirectPublisher;
use app\admin\logic\mqlogic\TransferConsumer;
use app\admin\logic\transfer_driver\Driver;
use app\common\model\zbtask\Money;
use fast\Random;
use Monolog\Handler\IFTTTHandler;
use think\Db;
use think\exception\ValidateException;


/**
 * 打款上层服务
 */
class Transfer
{

    private static $new; //申请一个私有的静态成员变量来保存该类的唯一实例
    private $payType;   //0为线下  1为线上
    private $data;      //本次打款数据
    private $moneyDb;     //money模型
    private $logDb;     //money模型
    private $where;
    private $extraWhere = [];
    private $extraData = [];
    private $transferType;
    static $exchange = 'transfer';  //扇形交换机
    static $queue = 'transfer_1';
    static $routeKey = 'transfer_1';
    private function __construct() {
        $this->moneyDb = new Money();
        $this->logDb = Db::name('zbtask_moneylog');
        $where['status'] = 1;  //有效
        $where['type'] = 1;    //审核通过
        $where['transfer_type'] = ['neq', 2];  //打款成功不能操作

        $this->where = $where;
    }


    public static function instance () { //声明一个静态公共方法，供外部获取唯一实例
        if (!(self::$new instanceof self)) {
            self::$new = new self;
        }
        return self::$new;
    }
    /**
     * 直连交换机
     */
    public function publisher($message) {
        $objMq = new DirectPublisher(config('site.rabitmqconfig'));
        $objMq->setExchange(self::$exchange)->setQueue(self::$queue)->setBindKey(self::$routeKey);

        $objMq->publish($message);
    }

    /**
     * 打款消费者
     */
    public function consumer() {
        $config = config('site.rabitmqconfig');
        $objConsumer = new TransferConsumer($config);
        $objConsumer->setQueue(self::$queue)->consume();

        return true;
    }
    /**设置支付类型*/
    public function setPayType($type, $transferType=null) {
        if (!in_array($type, [0, 1])) {
            throw new ValidateException('类型设置错误');
        }
        if ($type == 0) {
            if ($transferType === null) {
                throw new ValidateException('线下打款必须设置打款结果');
            }
            if (!in_array($transferType, [2, 3])) {
                throw new ValidateException('类型设置错误');
            }
            $this->transferType = $transferType;
        }
        $this->payType = $type;

        return $this;
    }

    /**设置外部where条件*/
    public function setWhere($where) {
        $this->extraWhere = $where;
        return $this;
    }

    /**获取列表数据*/
    public function getList() {
        $list = $this->moneyDb->where($this->extraWhere)->where($this->where)->select();
        $this->data = $list;
        return $this;
    }
    /** 额外更新数据*/
    public function setUpdate($data) {
        $this->extraData = $data;

        return $this;
    }

    /**
     * 打款
     */
    public function toTransfer($data = [], $callback = null) {
        if ($data) {
            $trans = $data;
        } else {
            $trans = $this->data;
        }

        if (!$trans) {
            throw new ValidateException('未设置打款数据');
        }
        if ($this->payType === null) {
            throw new ValidateException('请先设置打款类型');
        }
        if ($this->payType == 0) {
            $this->noOnline($trans, $callback);
        } else {
            $this->online($trans, $callback);
        }

        return true;
    }

    /**
     * 线下打款
     */
    public function noOnline($data, $callback = null) {
        if (!is_array($data)) {
            throw new ValidateException('必须为数组');
        }

        foreach ($data as $k => $v) {
            $this->checkTransfer($v);
            if ($callback instanceof \Closure) {
                $insertData = call_user_func_array( $callback , [$v]); //处理写入结果
            } else {
                $insertData['transfer_type'] = $this->transferType;  //打款状态
                $insertData['is_online'] = $this->payType;  //线上线下
                $insertData['pay_time'] = time();          //打款时间
                $insertData['order_sn'] = Random::uuid();
                $insertData['id'] = $v['id'];
            }
            $temp = array_merge($insertData, $this->extraData);
            $res = $this->moneyDb->update($temp);
            if ($res === false) {
                throw new ValidateException('更新失败');
            }

            $this->logNoOnline($v, $temp);
        }

        return true;
    }

    /**
     * 线上打款
     */
    public function online($data, $callback) {
        if (!is_array($data)) {
            throw new ValidateException('必须为数组');
        }

        foreach ($data as $k => $v) {
            $this->checkTransfer($v);
            if ($callback instanceof \Closure) {
                $insertData = call_user_func_array( $callback , [$v]); //处理写入结果
            } else {
                $insertData['transfer_type'] = 1;  //打款状态
                $insertData['is_online'] = $this->payType;  //线上线下
                $insertData['order_sn'] = Random::uuid();  //订单号
                $insertData['id'] = $v['id'];
            }
            $temp = array_merge($insertData, $this->extraData);
            $res = $this->moneyDb->where(['id' => $v['id']])->update($temp);

            if ($res === false) {
                throw new ValidateException('更新失败');
            }
            $message = ['money_id' => $v['id']];
            /*Transfer::instance()->driver( $v['id']);
            exit;*/
            //加入打款队列
            $this->publisher(json_encode($message));
        }

        return true;
    }
    //$v是众包费数组
    private function checkTransfer($v) {
        if ($v['transfer_type'] == 1) {
            throw new ValidateException('正在打款中...');
        }
        if ($v['transfer_type'] == 2) {
            throw new ValidateException('已打款成功不能重复打款');
        }
        if ($v['type'] != 1) {
            throw new ValidateException('审核未通过不能打款');
        }

        if ($v['status'] == 0) {
            throw new ValidateException('无效订单不能打款');
        }

        return true;
    }

    /**
     * 打款驱动分发
     */
    public function driver($money_id) {
        $moneyInfo = $this->moneyDb->where(['id'=>$money_id])->find();
        $transfer_config = config('transfer_config');
        $type = intval($moneyInfo['pay_type']);
        switch ($type) {
            case 0: $type = 'bank';break;
            case 1: $type = 'alipay';break;
            case 2: $type = 'wxpay';break;
            default: throw new ValidateException('打款类型错误');
        }

        $drive = $transfer_config['transfer'][$type];
        $platObj = Driver::getDriver($drive);
        $platObj->pay($money_id);
    }


    /**操作成功之后的日志表*/
    public function logNoOnline($v, $update) {
        //可以加入日志队列 去处理 这里直接写入
        $data['task_money_id'] = $v['id'];
        $data['createtime'] = time();
        $data['account'] = $v['bank_card'];
        $data['pay_type'] = $v['pay_type'];
        $data['msg'] = $update['remark'];
        $data['pay_plat'] = '线下打款';
        if ($update['transfer_type'] == 2) {
            $data['type'] = 1;
        } else {
            $data['type'] = 2;
        }

        $res = $this->logDb->insert($data);
        if ($res === false) {
            throw new ValidateException('打款失败');
        }

        return true;
    }
    //线上打款日志
    public function lineLog($id, $msg) {

    }


    private function __clone() {} //声明私有的克隆方法，防止对象被克隆

    public function __sleep() { //重写__sleep方法，将返回置空，防止序列化反序列化获得新的对象
        return [];
    }

}